import Vue from "vue";
import RouterView from "./components/RouterView";
import RouterLink from "./components/RouterLink";

// 全局注册 RouterView 和 RouterLink
Vue.component("RouterView", RouterView); 
Vue.component("RouterLink", RouterLink);

// 构建路由表 -- 构建路由的关联关系
class RouterTable {
  constructor(routes) {
    this._pathMap = new Map(); // 关联关系用map管理
    this.init(routes); // 初始化routes
  }
  init(routes) {
    // 将当前route添加到pathMap中
    const addRoute = route => {
      this._pathMap.set(route.path, route);

      // 如果有嵌套路由
      // if(route.children) {
        // 对children forEach 处理嵌套
      // }
    };

    // 遍历routes,对每个route进行addRoute操作
    routes.forEach(route => addRoute(route));
  }

  // 匹配当前path是否在_pathMap当中
  match(path) {
    let find;
    for (const key of this._pathMap.keys()) {
      if (path === key) {
        find = key;
        break;
      }
    }
    return this._pathMap.get(find);
  }
}
import Html5Mode from "./history/html5";

// 收集路由 和 销毁路由 hooks
function registerHook(list, fn) {
  list.push(fn);
  return () => {
    const i = list.indexOf(fn);
    if (i > -1) list.splice(i, 1);
  };
}

// 构造路由的类
export default class Router {
  constructor({ routes = [] }) {
    this.routerTable = new RouterTable(routes); // 构建路由表
    this.history = new Html5Mode(this); // 监听 
    /**
     * 两种model 建立history 有相似和差异的地方,采用模板模式,构建一个基类,
     * base.js 包括两种model都有的逻辑
     * hash.js 代表 hash model
     * html5.js 代表 html5 model
     */ 

    this.beforeHooks = []; // 路由before hooks
    this.resolveHooks = []; // 路由resolve hooks
    this.afterHooks = []; // 路由after hooks
  }
  init(app) {
    const { history } = this; // 将history 解构出来
    history.listen(route => { // 监听路由的改变,并重新赋值,会触发Vue.util.defineReactive 方法
      app._route = route;
    });
    // 执行页面的第一次跳转
    // history.transitionTo(history.getCurrentLocation());
  }
  push(to) {
    this.history.push(to);
  }

  // 对全局路由钩子的收集   
  beforeEach(fn) {
    return registerHook(this.beforeHooks, fn);
  }

  // 对全局路由钩子的收集
  beforeResolve(fn) {
    return registerHook(this.resolveHooks, fn);
  }

  // 对全局路由钩子的收集
  afterEach(fn) {
    return registerHook(this.afterHooks, fn);
  }
}

// 将自己的router 混入到 vue中
Router.install = function() {
  Vue.mixin({
    beforeCreate() {
      if (this.$options.router !== undefined) {
        this._routerRoot = this;
        this._router = this.$options.router;
        this._router.init(this); // 将vue 页面单应用注入

        // 将自己的router 转为 响应式的
        Vue.util.defineReactive(this, "_route", this._router.history.current);
      } else {
        this._routerRoot = this.$parent && this.$parent._routerRoot;
      }
    }
  });
};
